import numpy as np
import heapq

# 1. 数据生成
def generate_ecommerce_data(num_items=100, dimensions=10):
    """ 
    生成电商商品特征向量和用户特征向量
    :param num_items: 商品数量
    :param dimensions: 向量维度
    :return: 商品特征矩阵，用户特征向量
    """ 
    np.random.seed(42)
    item_vectors = np.random.rand(num_items, dimensions)
    user_vector = np.random.rand(1, dimensions)  # 模拟单个用户的兴趣特征向量
    return item_vectors, user_vector

# 生成数据（修正：移除了函数内部的重复调用）
item_vectors, user_vector = generate_ecommerce_data(num_items=100, dimensions=10)

# 2. HNSW索引实现
class HNSW:
    """ 
    实现HNSW用于近邻搜索
    """ 
    def __init__(self, vectors, max_neighbors=10, max_layers=4):
        self.vectors = vectors
        self.max_neighbors = max_neighbors
        self.max_layers = max_layers
        self.layers = self._construct_layers()

    def _construct_layers(self):
        layers = []
        current_vectors = self.vectors
        for layer_id in range(self.max_layers):
            layer = {i: [] for i in range(len(current_vectors))}
            for i in range(len(current_vectors)):
                distances = []
                for j in range(len(current_vectors)):
                    if i != j:
                        dist = np.linalg.norm(current_vectors[i] - current_vectors[j])
                        distances.append((dist, j))
                nearest_neighbors = heapq.nsmallest(self.max_neighbors, distances)
                layer[i] = [neighbor[1] for neighbor in nearest_neighbors]
            layers.append(layer)
            # 修正：正确的下采样方式，每层点数减半
            if len(current_vectors) > 1:
                current_vectors = current_vectors[:len(current_vectors)//2]
            else:
                break
        return layers

    def search(self, query_vector, top_k=5):
        """ 
        在HNSW中搜索与查询向量最相似的内容
        :param query_vector: 查询向量
        :param top_k: 返回前K个结果
        :return: 最相似的内容索引和距离
        """
        candidates = [(np.linalg.norm(query_vector - self.vectors[i]), i) 
                     for i in range(len(self.vectors))]
        return heapq.nsmallest(top_k, candidates)

# 3. 构建HNSW索引
hnsw_index = HNSW(item_vectors, max_neighbors=10, max_layers=4)

# 4. 查询推荐商品
def recommend_items(user_vector, hnsw_index, top_k=5):
    """
    为电商用户推荐商品
    :param user_vector: 用户兴趣特征向量
    :param hnsw_index: HNSW索引
    :param top_k: 推荐商品数量
    :return: 推荐商品索引和相似度
    """
    recommendations = hnsw_index.search(user_vector[0], top_k=top_k)
    return recommendations

recommendations = recommend_items(user_vector, hnsw_index, top_k=5)

# 5. 输出结果
print("用户特征向量:")
print(user_vector)
print("\n商品特征向量:")
print(item_vectors[:5])  # 仅展示前5个商品向量
print("\n推荐商品:")
for idx, (distance, item_idx) in enumerate(recommendations):
    print(f"推荐 {idx + 1}: 商品索引 {item_idx}, 相似度距离 {distance:.6f}")